package com.excilys.ymca.activity;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.DefaultHttpClient;

import roboguice.activity.GuiceActivity;
import roboguice.inject.InjectResource;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import com.excilys.ymca.R;
import com.excilys.ymca.util.SessionCookieHolder;
import com.google.inject.Inject;
import com.google.inject.Provider;

public class LoginToCasActivity extends GuiceActivity {

    private static final String         TAG                  = LoginToCasActivity.class.getSimpleName();

    private static final String         LOGIN_DENIED_PATH    = "/login/denied";
    private static final String         VALIDATE_PATH        = "/j_spring_cas_security_check";
    private static final String         TICKET_PARAM         = "?ticket=";

    private static final String         CAS_LOGIN_PATH       = "/login";
    private static final String         CAS_LOGOUT_PATH      = "/logout";
    private static final String         CAS_SERVICE_PARAM    = "?service=";
    private static final String         CAS_LOGOUT_URL_PARAM = "?url=";

    @InjectResource(R.string.cas_host)
    private String                      casHost;

    @InjectResource(R.string.zencontact_host)
    private String                      zencontactHost;

    @InjectResource(R.string.zencontact_service_host)
    private String                      zencontactServiceHost;

    @Inject
    private Provider<DefaultHttpClient> httpClientProvider;

    @Inject
    private SessionCookieHolder         sessionCookieHolder;

    private WebView                     loginView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        loginView = new WebView(this);

        setContentView(loginView);

        WebViewClient client = new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                Log.d(TAG, url);
                if (url.startsWith(zencontactServiceHost)) {
                    loginToZencontact(url);
                    return true;
                } else {
                    return false;
                }

            }
        };

        loginView.setWebViewClient(client);

        loginView.loadUrl(buildCasLoginUrl(true));
    }

    private String buildCasLoginUrl(boolean encode) {

        String serviceUrl = zencontactServiceHost + VALIDATE_PATH;

        if (encode) {
            serviceUrl = URLEncoder.encode(serviceUrl);
        }

        return casHost + CAS_LOGIN_PATH + CAS_SERVICE_PARAM + serviceUrl;
    }

    private String buildCasLogoutUrl() {
        return casHost + CAS_LOGOUT_PATH + CAS_LOGOUT_URL_PARAM + URLEncoder.encode(buildCasLoginUrl(false));
    }

    protected void loginToZencontact(final String url) {

        final String loginUrl = zencontactHost + VALIDATE_PATH + TICKET_PARAM
                + url.substring(url.lastIndexOf(TICKET_PARAM) + TICKET_PARAM.length());

        final ProgressDialog dialog = new ProgressDialog(this);
        dialog.setCancelable(false);
        dialog.setTitle(R.string.login_in_title);
        dialog.setMessage(getString(R.string.login_in_message));
        dialog.show();

        new AsyncTask<Void, Void, Exception>() {

            @Override
            protected Exception doInBackground(Void... params) {

                DefaultHttpClient httpClient = httpClientProvider.get();
                httpClient.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, false);

                HttpResponse response;
                try {
                    response = httpClient.execute(new HttpGet(loginUrl));
                } catch (IOException e) {
                    Log.e(TAG, "Error when login in to ZenContact", e);
                    return e;
                }

                Header locationHeader = response.getFirstHeader("location");

                if (locationHeader != null) {
                    String location = locationHeader.getValue();
                    if (location.startsWith(zencontactHost + LOGIN_DENIED_PATH)) {
                        return new IllegalStateException("Login failed, access denied");
                    }
                    Log.d(TAG, location);
                    Log.d(TAG, zencontactHost + LOGIN_DENIED_PATH);

                }

                List<Cookie> cookies = httpClient.getCookieStore().getCookies();

                for (Cookie cookie : cookies) {
                    if (cookie.getPath().equals("/zencontactdemo") && cookie.getName().equals("JSESSIONID")) {
                        sessionCookieHolder.setSessionCookie(cookie);
                        return null;
                    }
                }
                return new IllegalStateException("Session cookie not found");

            }

            @Override
            protected void onPostExecute(Exception exception) {
                dialog.cancel();
                if (exception != null) {
                    onLoginFailed(exception, url);
                } else {
                    startActivity(new Intent(LoginToCasActivity.this, ContactListActivity.class));
                }

            };
        }.execute();
    }

    protected void onLoginFailed(Exception exception, final String url) {

        String message = String.format(getString(R.string.login_failed_message), exception.getMessage());

        new AlertDialog.Builder(this)//
                .setTitle(R.string.login_failed_title) //
                .setCancelable(false) //
                .setMessage(message) //
                .setPositiveButton(R.string.retry, new OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        loginView.loadUrl(buildCasLogoutUrl());
                    }
                }) //
                .setNegativeButton(R.string.exit, new OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                })//
                .create()//
                .show();

    }
}
